import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { AddChargeOrder } from 'src/entities/AddChargeOrder';
import { ChargeOrder } from 'src/entities/ChargeOrder';
import { UserWallet } from 'src/entities/UserWallet';
import { UserWalletLog } from 'src/entities/UserWalletLog';
import { AddChargeOrderModelService } from 'src/model/add-charge-order-model/add-charge-order-model.service';
import { ChargeOrderModelService } from 'src/model/charge-order-model/charge-order-model.service';
import { RedisService } from 'src/redis/redis.service';
import { getTime } from 'src/util';
import { Connection } from 'typeorm';

@Injectable()
export class ChargeOrderService {
    private orderStatusKey = '';
    private addOrderStatusKey = '';
    private stopChargeStatusKey = '';
    private chargingOrderKey = '';
    constructor(
        private chargeOrderModelService:ChargeOrderModelService,
        private addChargeOrderModelService:AddChargeOrderModelService,
        private redis:RedisService,
        private configService:ConfigService,
        private connection: Connection,

    ) {
        this.orderStatusKey = this.configService.get<string>('cacheKey.chargeOrderStatus')
        this.addOrderStatusKey = this.configService.get<string>('cacheKey.addChargeOrderStatus')
        this.stopChargeStatusKey = this.configService.get<string>('cacheKey.stopChargeStatus')
        this.chargingOrderKey = this.configService.get<string>('cacheKey.chargingOrder')
    }

    async chargeNotify(orderId:number, errorCode:number) {
        try {
            let fields:(keyof ChargeOrder)[] = ['status', 'userId']
            if(errorCode != 0) {
                fields.push('feeAmount', 'feeRewardAmount', 'chargeAmount')
            }

            let order = await this.chargeOrderModelService.findOne({ orderId }, fields)
            if(!order) return false
            if(order.status != 0) {
                console.log('订单已处理完毕：', orderId)
                return true
            }

            let userId = order.userId
            let time = getTime()

            if(errorCode == 0) { //充电成功
                console.log('------------------设备上报充电成功 start --------------------')
                if(await this.chargeOrderModelService.update({ orderId }, {status : 1})) {
                    this.redis.set(this.orderStatusKey + orderId, 1, 'EX', 20) //状态设置为成功1
                    this.redis.redisClient.lpush(this.chargingOrderKey + userId, orderId) //加入正在充电

                    console.log('充电成功，订单处理完毕 end')

                    return true
                }else {
                    console.log('充电成功，订单处理失败 end')
                    return false
                }
            }else { //充电失败
                console.log('------------------设备上报充电失败 start --------------------')
                this.redis.set(this.orderStatusKey + orderId, 2, 'EX', 30) //状态设置为失败2

                let feeAmount = Number(order.feeAmount)
                let feeRewardAmount = Number(order.feeRewardAmount)
                
                const queryRunner = this.connection.createQueryRunner();
                await queryRunner.connect();
                await queryRunner.startTransaction()

                try {
                    console.log('--------------开始事务 -------------')
                    let wallet = await queryRunner.manager.findOne<UserWallet>(UserWallet, {
                        where : {userId : userId},
                        select : ['amount', 'rewardAmount'],
                        lock : {
                            mode : 'pessimistic_read'
                        }
                    })

                    let walletUpdate:{amount? : string, rewardAmount? : string} = {}
                    let walletLog:{[key in keyof UserWalletLog]? : UserWalletLog[key]} = {
                        userId : userId,
                        beforeAmount : wallet.amount,
                        beforeRewardAmount : wallet.rewardAmount,
                        afterAmount : wallet.amount,
                        afterRewardAmount : wallet.rewardAmount,
                        type : 3,
                        relationId : orderId
                    }

                    if(feeAmount > 0) { //有充值余额支出
                        walletUpdate.amount = String(feeAmount + Number(wallet.amount))
                        walletLog.amount = order.feeAmount
                        walletLog.afterAmount = walletUpdate.amount
                    }

                    if(feeRewardAmount > 0) { //有赠送余额支出的
                        walletUpdate.rewardAmount = String(feeRewardAmount + Number(wallet.rewardAmount))
                        walletLog.rewardAmount = order.feeRewardAmount
                        walletLog.afterRewardAmount = walletUpdate.rewardAmount
                    }

                    {
                        //更新钱包
                        const { raw } = await queryRunner.manager.update<UserWallet>(UserWallet, { userId }, walletUpdate)
                        if(!raw || raw.affectedRows < 1) {
                            await queryRunner.rollbackTransaction()

                            console.log('----- 更新钱包 失败 end ---------')

                            return false
                        }
                    }

                    {
                        //加入钱包明细
                        walletLog.createTime = time
                        const { raw } = await queryRunner.manager.insert<UserWalletLog>(UserWalletLog, walletLog)
                        if(!raw || raw.affectedRows < 1) {
                            await queryRunner.rollbackTransaction()

                            console.log('----- 加入钱包明细 失败 end ---------')

                            return false
                        }
                    }


                    {
                        //更新订单状态
                        const { raw } = await queryRunner.manager.update<ChargeOrder>(ChargeOrder, { orderId }, {status : 3, errorCode : errorCode})
                        if(!raw || raw.affectedRows < 1) {
                            await queryRunner.rollbackTransaction()
                            console.log('----- 更新订单状态 失败 end ---------')
                            return false
                        }
                    }
                    
                    await queryRunner.commitTransaction()

                    console.log('充电失败，订单事务处理完毕 end')

                    return true

                } catch (error) {
                    await queryRunner.rollbackTransaction()
                    console.log('----- 开始充电 设备上报事务出错 end ---------')
                    console.log(error)
                    return false
                }finally {
                    await queryRunner.release()
                }

            }
        } catch (error) {
            console.log('---- 开始充电 设备上报处理出错 --------')
            console.log(error)
        }finally {
            
        }

        return false
    }

    async addChargeNotify(orderId:number, errorCode:number) {
        let lockKey = 'ao:' + orderId
        if(await this.redis.set(lockKey, '', 'EX', 10, 'NX') === false) return false
        let chargeOder:ChargeOrder
        let order = await this.addChargeOrderModelService.findOne({ orderId }, ['status', 'relationOrderId', 'userId', 'feeAmount', 'feeRewardAmount', 'chargeAmount'])
        
        if(!order) return false

        if(order.status != 0) return true
        
        if(errorCode == 0) {
            chargeOder = await this.chargeOrderModelService.findOne({ orderId : order.relationOrderId }, ['feeAmount', 'feeRewardAmount', 'chargeAmount', 'status'])
            if(!chargeOder|| chargeOder.status != 1) return false
        }

        let time = getTime()
        const feeAmount = Number(order.feeAmount)
        const feeRewardAmount = Number(order.feeRewardAmount)

        const queryRunner = this.connection.createQueryRunner();
        await queryRunner.connect();
        await queryRunner.startTransaction()

        try {
            console.log('-------------增加充电 开始事务处理')


            if(errorCode == 0) {
                {
                    const { raw } = await queryRunner.manager.update<AddChargeOrder>(AddChargeOrder, { orderId }, {status : 1})
                    if(!raw || raw.affectedRows < 1) {
                        await queryRunner.rollbackTransaction()
                        console.log('-------------增加充电 更新增加订单失败')
                        return false
                    }
                }

                {
                    let updateData:{[key in keyof ChargeOrder]? : ChargeOrder[key]} = {
                        chargeAmount : String(Number(order.chargeAmount) + Number(chargeOder.chargeAmount))
                    }

                    if(feeAmount > 0) {
                        updateData.feeAmount = String(Number(chargeOder.feeAmount) + feeAmount)
                    }
                    if(feeRewardAmount > 0) {
                        updateData.feeRewardAmount = String(Number(chargeOder.feeRewardAmount) + feeRewardAmount)
                    }

                    const { raw } = await queryRunner.manager.update<ChargeOrder>(ChargeOrder, { orderId : order.relationOrderId }, updateData)
                    if(!raw || raw.affectedRows < 1) {
                        await queryRunner.rollbackTransaction()
                        console.log('-------------增加充电 更新充电订单失败')
                        return false
                    }

                }
                this.redis.set(this.addOrderStatusKey + orderId, 1, 'EX', 20) //状态设置为成功1
            }else {
                this.redis.set(this.addOrderStatusKey + orderId, 2, 'EX', 20) //状态设置为失败2

                let userId = order.userId

                let wallet = await queryRunner.manager.findOne<UserWallet>(UserWallet, {
                    where : {userId : userId},
                    select : ['amount', 'rewardAmount'],
                    lock : {
                        mode : 'pessimistic_read'
                    }
                })

                let walletUpdate:{amount? : string, rewardAmount? : string} = {}
                let walletLog:{[key in keyof UserWalletLog]? : UserWalletLog[key]} = {
                    userId : userId,
                    beforeAmount : wallet.amount,
                    beforeRewardAmount : wallet.rewardAmount,
                    afterAmount : wallet.amount,
                    afterRewardAmount : wallet.rewardAmount,
                    type : 4,
                    relationId : orderId
                }

                if(feeAmount > 0) { //有充值余额支出的
                    walletUpdate.amount = String(feeAmount + Number(wallet.amount))
                    walletLog.amount = order.feeAmount
                    walletLog.afterAmount = walletUpdate.amount
                }

                if(feeRewardAmount > 0) { //有赠送余额支出的
                    walletUpdate.rewardAmount = String(feeRewardAmount + Number(wallet.rewardAmount))
                    walletLog.rewardAmount = order.feeRewardAmount
                    walletLog.afterRewardAmount = walletUpdate.rewardAmount
                }

                {
                    //更新钱包
                    const { raw } = await queryRunner.manager.update<UserWallet>(UserWallet, { userId }, walletUpdate)
                    if(!raw || raw.affectedRows < 1) {
                        await queryRunner.rollbackTransaction()
                        return false
                    }
                }

                {
                    //加入钱包明细
                    walletLog.createTime = time
                    const { raw } = await queryRunner.manager.insert<UserWalletLog>(UserWalletLog, walletLog)
                    if(!raw || raw.affectedRows < 1) {
                        await queryRunner.rollbackTransaction()
                        return false
                    }
                }

                {
                    //更新订单状态
                    const { raw } = await queryRunner.manager.update<AddChargeOrder>(AddChargeOrder, { orderId }, {status : 2, errorCode : errorCode})
                    if(!raw || raw.affectedRows < 1) {
                        await queryRunner.rollbackTransaction()
                        return false
                    }
                }
            }

            await queryRunner.commitTransaction()

            return true


        } catch (error) {
            await queryRunner.rollbackTransaction()
            console.log('---------增加充电事务处理出错')
            console.log(error)
        }finally {
            await queryRunner.release()
            this.redis.del(lockKey)
        }

        return false
    }

    async stopChargeNotify(orderId:number, errorCode:number) {
        this.redis.set(this.stopChargeStatusKey + orderId, errorCode == 0 ? 1 : 2, 'EX', 60) //状态设置为失败2
    }

    async settlement(orderId:number, params:{totalTime:number; times:number[]; consumeEnergy:number; stopReason:number; maxPower:number; startTime:number; endTime:number}) {
        const lockKey = 'settlement:' + orderId
        if((await this.redis.set(lockKey, '', 'EX', 10, 'NX')) == false) return false

        const order = await this.chargeOrderModelService.findOne({ orderId }, ['status', 'strategyType', 'strategyRules', 'createTime', 'chargeAmount', 'unitPrice', 'settleUnit', 'feeAmount', 'feeRewardAmount', 'userId'])
        if(!order) return false

        if(order.status != 1) return true

        const chargeAmount = Number(order.chargeAmount)
        let consumeAmount = 0 //实际总共用了多少钱

        if(order.settleUnit == 0) { //不退费
            consumeAmount = chargeAmount
        }else {
            const unitPrice = Number(order.unitPrice)
            if(order.strategyType == 1) { //计时
                let rules:number[] = []
                for(let i = 0; i < 4; i ++) {
                    const rule = order.strategyRules[i]
                    if(rule) {
                        rules.push(rule.a)
                    }else {
                        rules.push(rules[i - 1])
                    }
                }

                params.times.forEach(t => {
                    const settleUnit = order.settleUnit * 60
                    consumeAmount += Math.ceil(t / settleUnit) *  settleUnit * unitPrice / 3600
                })
                
            }else { //计量
                consumeAmount = Math.ceil(params.consumeEnergy / order.settleUnit) * order.settleUnit * unitPrice
            }

            consumeAmount = Number(consumeAmount.toFixed(2))

            if(consumeAmount > chargeAmount) {
                consumeAmount = chargeAmount
            }

        }

        const time = getTime()
        
        let offsetTime = time - order.createTime

        if(params.totalTime > offsetTime) {
            params.totalTime = offsetTime
        }

        let updateData:{[key in keyof ChargeOrder]? : ChargeOrder[key]} = {
            status : 2,
            endTime : time,
            consumeAmount : String(consumeAmount),
            stopReason : params.stopReason,
            chargeData : {
                startChargeTime : params.startTime,
                endChargeTime : params.endTime,
                consumeTime : params.totalTime, //秒
                consumeEnergy : params.consumeEnergy,
                maxPower : params.maxPower,
                times : params.times
            }         
        }

        if(chargeAmount > consumeAmount) { //有退款
            console.log('---- 订单结算退款 ---------')

            let refundAmount = Number((chargeAmount - consumeAmount).toFixed(2)) //要退还的钱
            const userId = order.userId

            const queryRunner = this.connection.createQueryRunner();
            await queryRunner.connect();
            await queryRunner.startTransaction()

            try {
                let wallet = await queryRunner.manager.findOne<UserWallet>(UserWallet, {
                    where : {userId : userId},
                    select : ['amount', 'rewardAmount'],
                    lock : {
                        mode : 'pessimistic_read'
                    }
                })

                const orderFeeRewardAmount = Number(order.feeRewardAmount)

                let rechargeBalance = Number(wallet.amount) //充值的余额
                let rewardBalance = Number(wallet.rewardAmount) //赠送的余额

                let walletUpdate:{amount? : string, rewardAmount? : string} = {}
                let walletLog:{[key in keyof UserWalletLog]? : UserWalletLog[key]} = {
                    userId,
                    beforeAmount : wallet.amount,
                    beforeRewardAmount : wallet.rewardAmount,
                    afterAmount : wallet.amount,
                    afterRewardAmount : wallet.rewardAmount,
                    type : 5,
                    relationId : orderId,
                }

                if(orderFeeRewardAmount >= refundAmount) { //全部退还到赠送余额
                    walletUpdate.rewardAmount = String(refundAmount + rewardBalance)

                    walletLog.rewardAmount = String(refundAmount)
                    walletLog.afterRewardAmount = walletUpdate.rewardAmount
                    
                }else {
                    const offset = refundAmount - orderFeeRewardAmount //这是要退给充值余额的钱

                    walletUpdate.amount = String(offset + rechargeBalance)
                    walletLog.amount = String(offset)
                    walletLog.afterAmount = walletUpdate.amount

                    if(orderFeeRewardAmount > 0) {
                        walletUpdate.rewardAmount = String(rewardBalance + orderFeeRewardAmount)
                        walletLog.rewardAmount = order.feeRewardAmount
                        walletLog.afterRewardAmount = walletUpdate.rewardAmount
                    }
                }

                {
                    //更新钱包
                    const { raw } = await queryRunner.manager.update<UserWallet>(UserWallet, { userId }, walletUpdate)
                    if(!raw || raw.affectedRows < 1) {
                        await queryRunner.rollbackTransaction()
                        return false
                    }
                }

                {
                    //加入钱包明细
                    walletLog.createTime = time
                    const { raw } = await queryRunner.manager.insert<UserWalletLog>(UserWalletLog, walletLog)
                    if(!raw || raw.affectedRows < 1) {
                        await queryRunner.rollbackTransaction()
                        return false
                    }
                }

                {
                    //更新订单
                    const { raw } = await queryRunner.manager.update<ChargeOrder>(ChargeOrder, { orderId }, updateData)
                    if(!raw || raw.affectedRows < 1) {
                        await queryRunner.rollbackTransaction()
                        return false
                    }
                }


                await queryRunner.commitTransaction()

                console.log('订单结算完成')

                return true

            } catch (error) {
                await queryRunner.rollbackTransaction()
                console.log('------- 结算订单事务错误-------------')
                console.log(error)
            }finally {
                await queryRunner.release()
            }

        }else {
            //更新订单
            const res = await this.chargeOrderModelService.update({ orderId }, updateData);
            console.log('订单结算完成1')
            return res ? true : false
        }

    }
}
